/* refatorar o codigo abaixo pra ficar bem feito*/

#include "listFactory.h"
#include <errno.h>

#ifndef TRUE
	#define TRUE 1
#endif
#ifndef FALSE
	#define FALSE 0
#endif


/*newList: sem parametros, maloca espa�o do tamanho de uma estrutura Noh, definida
dentro de listFactory.h , e seta tanto o proximo do primeiro elemento quanto o ultimo
 elemento da lista igual ao ponteiro retornado pelo malloc (n�o eh setado em null pra
diminuir a chance de null pointers resultarem em segmentation fault)*/
List* newList (){

	List* newList= (List*) malloc ( sizeof (List));

	if (newList == NULL){

	}

	/*tendo certeza que o tamanho de uma lista recem criada por esta funcao eh zero*/
	newList->length =0;
	newList->acceptNullEntries =TRUE;

	newList->first= NULL;
	newList->last= NULL;

	return newList;
}

/*newNode: sem parametros, maloca espa�o do tamanho de uma estrutura Noh, definida
dentro de listFactory.h , e seta tanto o proximo do noh mallocado quanto o ultimo
 elemento do Noh igual a NULL*/
Noh* newNode (){

	Noh* novoNoh= (Noh*) malloc ( sizeof ( Noh));

	//deu pau no malloc
	if (novoNoh == NULL){


		return NULL;
	}

	novoNoh->prev= NULL;
	novoNoh->prox= NULL;
	return novoNoh;
}

Noh* newNodeWithData (void* dados){


	Noh* novoNoh= newNode();

	if (novoNoh == NULL){
		return NULL;
	}

	novoNoh->dados = dados;

	return novoNoh;
}

int setProxNoh( Noh* noh, Noh* proxNoh){

	if (noh == NULL || proxNoh == NULL){
		return -1;
	}

	noh->prox = proxNoh;
	return 0;

}

int setPrevNoh( Noh* noh, Noh* nohAnterior){

	if (noh == NULL || nohAnterior == NULL){
		return -1;
	}

	noh->prev = nohAnterior;

	return 0;
}


/*isEmptyList : funcao que confere se uma lista est� ou nao vazia
conferindo se o length dela eh zero ou nao*/
int isEmptyList (List *list){

	if (list == NULL){
		puts("Erro em isEmptyList: lista passada como parametro eh nula");
		return -1;
	}

	if ( list->length ==0)	{return 1;}
	else {return TRUE;}
}

int isNullList (List *list){

	if ( list == NULL)
		return TRUE;
	else return FALSE;
}

int getListSize (List *list){

	if (list == NULL){
		puts("Erro em isEmptyList: lista passada como parametro eh nula");
		return -1;
	}

	return list->length;
}


void* get (List *list, int position){

	if (list == NULL){
		puts("Erro em listFactory.get : lista passada como parametro eh nula");
		return NULL;
	}

	if (position <= 0){
		puts("Erro em listFactory.get : posicao para recuperacao do noh na lista eh menor ou igual a zero");
		return NULL;
	}

	if (position > list->length){
			puts("Erro em listFactory.get : posicao para recuperacao do noh na lista eh maior que o tamanho da lista");
			return NULL;
	}


	int listSize= 0;
	if (list != NULL){ listSize = list->length;}


	Noh *n = list->first;
	int i =0;
	for ( i = 0; i < listSize; ++i) {
		if (position == i){
			return (void *)n;
		}
		n= n->prox;
	}

	return NULL;

}

/**Aqui acabam as funcoes que lidam diretamente com a lista em si
 *
TODO : refatorar o codigo abaixo pra usar as funcoes de cima para acessar campos da lista*/

int addAsFirst ( List *list, void *elemento ){

	if (list == NULL){
		puts("Erro em addAsFirst: lista passada como parametro eh nula");
		return -1;
	}

	Noh* novoNoh = newNodeWithData(elemento);

	if (novoNoh == NULL){
		puts("Erro em addAsFirst: chamada a newNodeWithData(elemento) retorna null");
		return -1;
	}

	list->length+=1;

	setProxNoh(novoNoh, list->first);

	setPrevNoh(list->first, novoNoh);

	list->first= novoNoh;
	return 0;
}

/*quando implementar o size do Noh, trocar o sizeof abaixo pelo size do Noh*/
void add ( List *list, void *elemento ){

	if (list == NULL){
		puts("Erro em addAsLast: lista passada como parametro eh nula");
		exit(1);
	}

	Noh* novoNoh = newNodeWithData(elemento);

	list->length+=1;

	setPrevNoh(novoNoh, list->last);

	setProxNoh(list->last, novoNoh);

	list->last= novoNoh;

	/* Codigo do Marco pro insereLista()

	Noh* novoNoh = (Noh *) malloc ( sizeof ( Noh *) );

	inicio->prev->prox=novoNoh;
	inicio->prev->prox->prev=inicio->prev;
	inicio->prev->prox->dados=elemento;
	inicio->prev=inicio->prev->prox;
	inicio->prev->prox=inicio;
	*/

}

void addAsNth ( List *list, void *elemento, int position ){

	if (list == NULL){
		puts("Erro em addAsNth: lista passada como parametro eh nula");
		exit(1);
	}

	if (position <= 0){
		puts("Erro em addAsNth: posicao para insercao do noh na lista eh menor ou igual a zero");
		exit(1);
	}

	Noh* novoNoh = newNodeWithData(elemento);

	list->length+=1;

	setPrevNoh(novoNoh, list->last);

	setProxNoh(list->last, novoNoh);

	list->last= novoNoh;

}



/*guarda um ponteiro com o endere�o do proximo do primeiro
e vai mudando um aux. enquanto aux nao for igual a copia,
vai imprimindo o conteudo e mudando o aux */

/**essa funcao ainda nao tah completa, pq ainda nao achei um jeito de imprimir
os elementos de dentro da lista sem saber o que eles sao (void* nao eh muita ajuda xD)*/
/*void printList ( Noh *inicio ){

	Noh *aux;
	aux=inicio->prev;
	while ( aux != inicio ){
		printf ( "%lf,%lf\n", aux->dados->x, aux->dados->y);
		aux=aux->prev;
	}

}
*/

/**essa funcao ainda nao tah completa, pq ainda nao achei um jeito de imprimir
os elementos de dentro da lista (void* nao eh muita ajuda xD)*/
void saveListToFile ( List *lista, char* nomeArquivo  ){

	if (nomeArquivo == NULL){
		puts ("Erro em saveListToFile: nome do arquivo eh NULL");
		exit(-1);
	}

	FILE* fileFp;

	fileFp = fopen (nomeArquivo, "w");

	if ( fileFp == NULL){
		puts ("Erro em fopen: fopen retorna NULL ao abrir o arquivo para guardar a lista");
		exit(-1);
	}


}

// void saveListToFile ( Noh *inicio, char* nomeArquivo  ){
//
// 	if (nomeArquivo == NULL){
// 		puts ("Erro em saveListToFile: nome do arquivo eh NULL");
// 		exit;
// 	}
//
// 	Noh *aux;
// 	aux=inicio->prox;
// 	FILE* fileFp;
//
// 	fileFp = fopen (nomeArquivo, "w");
//
// 	if ( fileFp == NULL){
// 		puts ("Erro em fopen: fopen retorna NULL ao abrir o arquivo para guardar a lista");
// 		exit(-1);
// 	}
//
// 	while ( aux != inicio ){
// 		fprintf (respFp, "(%lf,%lf)\n", aux->dados->x, aux->dados->y);
// 		aux=aux->prox;
// 	}
// }

/*recebe um noh pra come�ar a busca pelo noh a deletar, e um int
 com  a posicao dele na lista. se a lista nao for circular, a
 funcao dah pau. senao remove o noh e arruma os ponteiros.*/
/*void* remove ( Noh *inicio,  int posicao ){

	void* retirado;
	if ( vazia (inicio) )
		puts ( "erro: lista vazia" );
	else{
		Noh* aux=inicio->prox;
		int i=1;
		while ( i < posicao && aux != inicio ){
			aux=aux->prox;
			i++;
		}
		if ( aux == inicio )
			puts ( "erro: posicao invalida" );
		else{
			retirado=aux->dados;
			//proximo do anterior agora eh o proximo do atual, pq o atual vai ser removido
			aux->prev->prox=aux->prox;
			//anterior do proximo agora eh o anterior do atual, pq o atual vai ser removido
			aux->prox->prev=aux->prev;
			//libera o atual
			free ( aux );
		}
	}
	return retirado;
}
*/

